<template>
  <div class="code-container" ref="container" :style="{height:height+'px'}"></div>
</template>

<script>
import * as monaco from 'monaco-editor/esm/vs/editor/editor.main.js';
import languagesHints from "@/components/languagesHints";

export default {
  name: "codeEditor",

  props: {
    options: {
      type: Object,
      default() {
        return {};
      }
    },

    value: {
      type: String,
      default: ""
    },
    height: {
      type: Number,
      default: 300
    }
  },

  data() {
    return {
      monacoInstance: null
    };
  },
  mounted() {
    this.register();
    this.init();
  },
  beforeDestroy() {
    this.dispose();
  },
  watch: {
    options: {
      handler(val) {
        this.init()
      },
      deep: true
    }
  },
  methods: {
    register() {
      for (let languagesHintsKey in languagesHints) {

        monaco.languages.registerCompletionItemProvider(languagesHintsKey, {
          provideCompletionItems: (model, position) => {
            var textUntilPosition = model.getValueInRange({
              startLineNumber: position.lineNumber,
              startColumn: 1,
              endLineNumber: position.lineNumber,
              endColumn: position.column
            });
            var suggestions = this.createCompleters(textUntilPosition, languagesHints[languagesHintsKey]);
            return {
              suggestions: suggestions
            };
          }
        });

      }
    },
    init() {
      this.dispose();
      // 编辑器配置
      this.editorOptions = {
        // 编辑器的值
        value: this.value,
        // 编辑器主题：vs, hc-black, or vs-dark，更多选择详见官网
        theme: "vs",
        // 自动缩进
        autoIndex: true,
        scrollBeyondLastLine: false,
        // 右侧不显示编辑器预览框
        // roundedSelection: false,
        language: "sql", // shell、sql、python
        readOnly: false, // 不能编辑
        minimap: {
          enabled: false
        },
        ...this.options
      }
      // 初始化编辑器实例
      this.monacoInstance = monaco.editor.create(this.$refs.container, this.editorOptions);

      // 监听编辑器content变化事件
      this.monacoInstance.onDidChangeModelContent(() => {
        this.$emit("contentChange", this.monacoInstance.getValue());
      });
    },
    // 供父组件调用手动获取值
    getVal() {
      return this.monacoInstance.getValue()
    },
    createCompleters(textUntilPosition, $hints = []) {
      //过滤特殊字符
      let _textUntilPosition = textUntilPosition
          .replace(/[\*\[\]@\$\(\)]/g, "")
          .replace(/(\s+|\.)/g, " ");
      //切割成数组
      let arr = _textUntilPosition.split(" ");
      //取当前输入值
      let activeStr = arr[arr.length - 1];
      //获得输入值的长度
      let len = activeStr.length;

      //获得编辑区域内已经存在的内容
      let rexp = new RegExp('([^\\w]|^)' + activeStr + '\\w*', "gim");
      let match = this.value.match(rexp);
      let _hints = !match ? [] : match.map(ele => {
        let rexp = new RegExp(activeStr, "gim");
        let search = ele.search(rexp);
        return ele.substr(search)
      })

      //查找匹配当前输入值的元素
      let hints = Array.from(new Set([...$hints, ..._hints])).sort().filter(ele => {
        let rexp = new RegExp(ele.substr(0, len), "gim");
        return match && match.length === 1 && ele === activeStr || ele.length === 1
            ? false
            : activeStr.match(rexp);
      });
      //添加内容提示
      return hints.map(ele => {
        return {
          label: ele,
          kind: $hints.indexOf(ele) > -1 ? monaco.languages.CompletionItemKind.Keyword : monaco.languages.CompletionItemKind.Text,
          documentation: ele,
          insertText: ele
        };
      });
    },
    dispose() {
      if (this.monacoInstance) {
        if (this.monacoInstance.getModel()) {
          this.monacoInstance.getModel().dispose();
        }
        this.monacoInstance.dispose();
        this.monacoInstance = null;
        // if (this.provider) {
        //   this.provider.dispose();
        //   this.provider = null
        // }
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.code-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
  border: 1px solid #eaeaea;

  .monaco-editor .scroll-decoration {
    box-shadow: none;
  }
}
</style>
